home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / text / edit / Reversed15.lha / Reversed / source / main.c
Encoding:
C/C++ Source or Header  |  1995-04-17  |  14.7 KB  |  581 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  Reversed API client, ©1995 Dietmar Eilert. Dice:
  4.  
  5.  dcc main.c -// -proto -mi -l reqtoolssr.lib -r -2.0 -o ram:reversed
  6.  
  7.   ------------------------------------------------------------------------------
  8. */
  9.  
  10. /// "includes"
  11.  
  12. #define Prototype extern
  13.  
  14. #include <exec/exec.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <dos/dos.h>
  19. #include <dos/dostags.h>
  20. #include <dos/rdargs.h>
  21. #include <intuition/intuition.h>
  22. #include <utility/tagitem.h>
  23. #include <workbench/startup.h>
  24. #include <rexx/errors.h>
  25. #include <rexx/rxslib.h>
  26. #include <clib/exec_protos.h>
  27. #include <clib/dos_protos.h>
  28. #include <clib/intuition_protos.h>
  29. #include <clib/rexxsyslib_protos.h>
  30. #include <clib/alib_protos.h>
  31. #include <clib/reqtools_protos.h>
  32.  
  33. #include "golded:api/include/golded.h"
  34.  
  35. Prototype void   main(int, char **);
  36. Prototype int    wbmain(struct WBStartup *);
  37. Prototype void   HandleAPI(char *, struct Settings *);
  38. Prototype ULONG *SendRexxCommand(char *, char *, struct MsgPort *, char *);
  39. Prototype void   Dispatch(struct APIMessage *, struct Settings *);
  40. Prototype LONG   CommandReversedHandler(ULONG *, struct APIMessage *, struct Settings *);
  41. Prototype void   HandleUserInput(struct APIMessage *, struct Settings *);
  42. Prototype BOOL   EvaluateBool(UBYTE *, BOOL);
  43. Prototype void   DoBackspaceReversed(struct APIMessage *, struct EditConfig *);
  44. Prototype void   DoDeleteReversed(struct APIMessage *, struct EditConfig *);
  45.  
  46. // globals
  47.  
  48. struct Library *ReqToolsBase;
  49.  
  50. struct Settings {
  51.  
  52.     BOOL Active;
  53. };
  54.  
  55. ///
  56. /// "main"
  57.  
  58. int
  59. wbmain(struct WBStartup *startup)
  60. {
  61.     if (ReqToolsBase = OpenLibrary("reqtools.library", 37)) {
  62.  
  63.         rtEZRequestTags("No executable - to be used as API client", "OK", NULL, NULL, TAG_DONE);
  64.  
  65.         CloseLibrary(ReqToolsBase);
  66.     }
  67. }
  68.  
  69. void
  70. main(int argc, char **argv)
  71. {
  72.     static UBYTE version[] = "$VER: Reversed 1.5 (" __COMMODORE_DATE__ ")";
  73.  
  74.     ULONG argArray[] = { 0, 0, 0, 0, 0 };
  75.  
  76.     struct RDArgs *rdArgs;
  77.  
  78.     if (rdArgs = ReadArgs("H=HOST/K/A", argArray, NULL)) {
  79.  
  80.         struct Settings settings = { TRUE };
  81.  
  82.         HandleAPI((UBYTE *)argArray[0], &settings);
  83.  
  84.         FreeArgs(rdArgs);
  85.     }
  86.  
  87.     exit(0);
  88. }
  89.  
  90. ///
  91. /// "api management"
  92.  
  93. /* --------------------------------- HandleAPI ---------------------------------
  94.  
  95.  Register with GoldED & handle incoming API messages.
  96.  
  97. */
  98.  
  99. void
  100. HandleAPI(host, settings)
  101.  
  102. char            *host;
  103. struct Settings *settings;
  104. {
  105.     struct MsgPort *apiPort, *rexxPort;
  106.  
  107.     if (apiPort = CreateMsgPort()) {
  108.  
  109.         if (rexxPort = CreateMsgPort()) {
  110.  
  111.             UBYTE command[255];
  112.             ULONG *result;
  113.  
  114.             sprintf(command, "API PORT=%ld CLASS=%ld", apiPort, API_CLASS_ROOT | API_CLASS_KEY | API_CLASS_REXX);
  115.  
  116.             if (result = SendRexxCommand(host, command, rexxPort, NULL)) {
  117.  
  118.                 if (*result == RC_OK) {
  119.  
  120.                     BOOL active = TRUE;
  121.  
  122.                     do {
  123.  
  124.                         struct APIMessage *apiMsg, *nextMsg;
  125.  
  126.                         while (!(apiMsg = (struct APIMessage *)GetMsg(apiPort)))
  127.                             WaitPort(apiPort);
  128.  
  129.                         do {
  130.  
  131.                             for (nextMsg = apiMsg; nextMsg; nextMsg = nextMsg->api_Next) {
  132.  
  133.                                 if (nextMsg->api_State == API_STATE_NOTIFY) {
  134.  
  135.                                     switch (nextMsg->api_Class) {
  136.  
  137.                                         case API_CLASS_ROOT:
  138.  
  139.                                             switch (nextMsg->api_Action) {
  140.  
  141.                                                 case API_ACTION_DIE:
  142.  
  143.                                                     active = FALSE;
  144.                                                     break;
  145.  
  146.                                                 case API_ACTION_INTRODUCE:
  147.  
  148.                                                     static struct TagItem tags[] = {
  149.  
  150.                                                         API_Client_Name,      "Reversed",
  151.                                                         API_Client_Copyright, "Reversed ©1995 Dietmar Eilert",
  152.                                                         API_Client_Purpose,   "Right-To-Left input handler",
  153.                                                         API_Client_Template,  "REVERSED USE/K,BACK/S,DEL/S",
  154.                                                         API_Client_Template,  "NEWLINE",
  155.                                                         TAG_DONE
  156.                                                     };
  157.  
  158.                                                     nextMsg->api_Data = tags;
  159.                                                     break;
  160.  
  161.                                                 default:
  162.  
  163.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  164.                                             }
  165.  
  166.                                             break;
  167.  
  168.                                         case API_CLASS_KEY:
  169.  
  170.                                             switch (nextMsg->api_Action) {
  171.  
  172.                                                 case API_ACTION_VANILLAKEY:
  173.  
  174.                                                     HandleUserInput(nextMsg, settings);
  175.                                                     break;
  176.  
  177.                                                 default:
  178.  
  179.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  180.                                             }
  181.                                             break;
  182.  
  183.                                         case API_CLASS_REXX:
  184.  
  185.                                             switch (nextMsg->api_Action) {
  186.  
  187.                                                 case API_ACTION_COMMAND:
  188.  
  189.                                                     Dispatch(nextMsg, settings);
  190.                                                     break;
  191.  
  192.                                                 default:
  193.  
  194.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  195.                                             }
  196.                                             break;
  197.  
  198.                                         default:
  199.  
  200.                                             nextMsg->api_Error = API_ERROR_UNKNOWN;
  201.                                     }
  202.                                 }
  203.                             }
  204.  
  205.                             ReplyMsg((struct Message *)apiMsg);
  206.  
  207.                         } while (apiMsg = (struct APIMessage *)GetMsg(apiPort));
  208.  
  209.                     } while (active);
  210.                 }
  211.             }
  212.  
  213.             DeleteMsgPort(rexxPort);
  214.         }
  215.  
  216.         DeleteMsgPort(apiPort);
  217.     }
  218. }
  219.  
  220.  
  221. ///
  222. /// "command dispatcher"
  223.  
  224. /* --------------------------------- Dispatch ----------------------------------
  225.  
  226.  Dispatch incoming command: examine command string (command part is uppercase
  227.  already), look for handler function related to command, parse arguments (if 
  228.  command supports arguments), call handler.
  229.  
  230. */
  231.  
  232. void
  233. Dispatch(apiMsg, settings)
  234.  
  235. struct APIMessage *apiMsg;
  236. struct Settings   *settings;
  237. {
  238.     struct RDArgs *rdArgs, *args;
  239.  
  240.     if (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) {
  241.  
  242.         static char buffer[1024];
  243.  
  244.         // table of supported commands, associated handlers & template strings
  245.  
  246.         static struct parser { char *command; LONG (*handler)(ULONG *, struct APIMessage *, struct Settings *); char *template; } parser[] = {
  247.  
  248.             "REVERSED",  (APTR)CommandReversedHandler,  "USE/K,BACK/S,DEL/S",
  249.              NULL
  250.         };
  251.  
  252.         ULONG n, argArray[] = { 0, 0, 0, 0, 0, 0 };
  253.  
  254.         struct APIRexxNotify *notify = (struct APIRexxNotify *)apiMsg->api_Data;
  255.  
  256.         // make LF-terminated copy of command string (required by dos/readArgs):
  257.  
  258.         strcpy(buffer, notify->arn_Command);
  259.  
  260.         strcat(buffer, "\12");
  261.  
  262.         for (n = 0; parser[n].command; ++n) {
  263.  
  264.             if (!memcmp(buffer, parser[n].command, strlen(parser[n].command))) {
  265.  
  266.                 char *arguments = buffer + strlen(parser[n].command);
  267.  
  268.                 rdArgs->RDA_Source.CS_Buffer = arguments;
  269.                 rdArgs->RDA_Source.CS_Length = strlen(arguments);
  270.                 rdArgs->RDA_Source.CS_CurChr = 0;
  271.                 rdArgs->RDA_DAList           = NULL;
  272.                 rdArgs->RDA_Buffer           = NULL;
  273.  
  274.                 if (parser[n].template) {
  275.  
  276.                     if (args = ReadArgs(parser[n].template, argArray, rdArgs)) {
  277.  
  278.                         notify->arn_RC = (*parser[n].handler)(argArray, apiMsg, settings);
  279.  
  280.                         FreeArgs(args);
  281.                     }
  282.                     else {
  283.  
  284.                         static UBYTE errorText[81];
  285.  
  286.                         notify->arn_RC           = RC_WARN;
  287.                         notify->arn_CommandError = errorText;
  288.  
  289.                         Fault(IoErr(), "IoErr()", errorText, 80);
  290.                     }
  291.                 }
  292.                 else
  293.                     notify->arn_RC = (*parser[n].handler)(argArray, apiMsg, settings);
  294.             }
  295.         }
  296.  
  297.         FreeDosObject(DOS_RDARGS, rdArgs);
  298.     }
  299. }
  300.  
  301. /* -------------------------- CommandReversedHandler ---------------------------
  302.  
  303.  Handle REVERSED command
  304.  
  305.  template: USE/K,BACK/S,DEL/S
  306.  
  307. */
  308.  
  309. LONG
  310. CommandReversedHandler(argArray, apiMsg, settings)
  311.  
  312. struct APIMessage *apiMsg;
  313. struct Settings   *settings;
  314. ULONG             *argArray;
  315. {
  316.     struct EditConfig *config = apiMsg->api_Config;
  317.  
  318.     apiMsg->api_State = API_STATE_CONSUMED;
  319.  
  320.     if (argArray[0])                                 // USE/K
  321.         settings->Active = EvaluateBool((char *)argArray[0], settings->Active);
  322.  
  323.     if (argArray[1])                                 // BACK/S
  324.         DoBackspaceReversed(apiMsg, config);
  325.  
  326.     if (argArray[2])                                 // DEL/S
  327.         DoDeleteReversed(apiMsg, config);
  328.  
  329.     return(RC_OK);
  330. }
  331.  
  332. /* ---------------------------- DoBackspaceReversed ----------------------------
  333.  
  334.  Backspace in reversed-input mode
  335.  
  336. */
  337.  
  338. void
  339. DoBackspaceReversed(apiMsg, config)
  340.  
  341. struct APIMessage *apiMsg;
  342. struct EditConfig *config;
  343. {
  344.     static struct APIModifyRequest modifyRequest;
  345.  
  346.     static UBYTE buffer[4096];
  347.  
  348.     UWORD len;
  349.  
  350.     if (len = config->CurrentLen)
  351.         movmem(config->CurrentBuffer, buffer, len);
  352.  
  353.     ++config->Column;
  354.  
  355.     // expand line in case we moved beyond the end of line
  356.  
  357.     while (len <= config->Column)
  358.         buffer[len++] = 32;
  359.  
  360.     if (config->LineNotFixed) {
  361.  
  362.         movmem(buffer, buffer + 1, config->Column);
  363.  
  364.         buffer[0] = 32;
  365.     }
  366.  
  367.     modifyRequest.mr_Next   = NULL;
  368.     modifyRequest.mr_Line   = config->Line;
  369.     modifyRequest.mr_Column = config->Column;
  370.     modifyRequest.mr_Data   = buffer;
  371.     modifyRequest.mr_Size   = len;
  372.  
  373.     apiMsg->api_Modify = &modifyRequest;
  374. }
  375.  
  376. /* ------------------------------ DoDeleteReversed -----------------------------
  377.  
  378.  Delete in reversed-input mode
  379.  
  380. */
  381.  
  382. void
  383. DoDeleteReversed(apiMsg, config)
  384.  
  385. struct APIMessage *apiMsg;
  386. struct EditConfig *config;
  387. {
  388.     static struct APIModifyRequest modifyRequest;
  389.  
  390.     static UBYTE buffer[4096];
  391.  
  392.     UWORD len;
  393.  
  394.     if (len = config->CurrentLen)
  395.         movmem(config->CurrentBuffer, buffer, len);
  396.  
  397.     if (config->LineNotFixed) {
  398.  
  399.         if (config->Column)
  400.             movmem(config->CurrentBuffer, buffer + 1, config->Column);
  401.  
  402.         *buffer = 32;
  403.     }
  404.  
  405.     modifyRequest.mr_Next   = NULL;
  406.     modifyRequest.mr_Line   = config->Line;
  407.     modifyRequest.mr_Column = config->Column;
  408.     modifyRequest.mr_Size   = len;
  409.     modifyRequest.mr_Data   = buffer;
  410.  
  411.     apiMsg->api_Modify = &modifyRequest;
  412. }
  413.  
  414. ///
  415. /// "input handler"
  416.  
  417. /* ------------------------------ HandleUserInput ------------------------------
  418.  
  419.  Handle user input
  420.  
  421. */
  422.  
  423. void
  424. HandleUserInput(apiMsg, settings)
  425.  
  426. struct APIMessage *apiMsg;
  427. struct Settings   *settings;
  428. {
  429.     if (settings->Active) {
  430.  
  431.         struct EditConfig *editConfig = apiMsg->api_Config;
  432.  
  433.         if (editConfig->LineNotFixed) {
  434.  
  435.             static struct APIModifyRequest modifyRequest;
  436.  
  437.             static UBYTE buffer[4096];
  438.  
  439.             UWORD column, len;
  440.  
  441.             editConfig = apiMsg->api_Config;
  442.  
  443.             column = editConfig->Column;
  444.             len    = editConfig->CurrentLen;
  445.  
  446.             // get contents of current line
  447.  
  448.             movmem(editConfig->CurrentBuffer, buffer, len);
  449.  
  450.             // shift text to the left (i.e. delete first character)
  451.  
  452.             if (column)
  453.                 movmem(buffer + 1, buffer, column);
  454.  
  455.             // insert character
  456.  
  457.             while (len <= column)
  458.                 buffer[len++] = 32;
  459.  
  460.             buffer[column] = (UBYTE)apiMsg->api_Data;
  461.  
  462.             // move cursor to the left
  463.  
  464.             if (column)
  465.                 --column;
  466.  
  467.             // send modify request to the editor
  468.  
  469.             modifyRequest.mr_Next   = NULL;
  470.             modifyRequest.mr_Line   = editConfig->Line;
  471.             modifyRequest.mr_Column = column;
  472.             modifyRequest.mr_Size   = len;
  473.             modifyRequest.mr_Data   = buffer;
  474.  
  475.             apiMsg->api_Modify = &modifyRequest;
  476.         }
  477.  
  478.         // remove input event from input stream
  479.  
  480.         apiMsg->api_State = API_STATE_CONSUMED;
  481.     }
  482. }
  483.  
  484. /// "arexx"
  485. /// "arexx"
  486.  
  487. /* ---------------------------------- SendRexxCommand -------------------------
  488.  
  489.  Send ARexx message & wait for answer. Return pointer to result or NULL.
  490.  
  491. */
  492.  
  493. ULONG *
  494. SendRexxCommand(port, cmd, replyPort, buffer)
  495.  
  496. char   *cmd, *port, *buffer;
  497. struct MsgPort *replyPort;
  498. {
  499.     struct MsgPort *rexxport;
  500.  
  501.     Forbid();
  502.  
  503.     if (rexxport = FindPort(port)) {
  504.  
  505.         struct RexxMsg *rexxMsg, *answer;
  506.  
  507.         if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
  508.  
  509.             if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
  510.  
  511.                 static ULONG result;
  512.  
  513.                 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
  514.  
  515.                 PutMsg(rexxport, &rexxMsg->rm_Node);
  516.  
  517.                 do {
  518.                     
  519.                     WaitPort(replyPort);
  520.  
  521.                     if (answer = (struct RexxMsg *)GetMsg(replyPort))
  522.                         result = answer->rm_Result1;
  523.  
  524.                 } while (!answer);
  525.  
  526.                 Permit();
  527.  
  528.                 if (answer->rm_Result1 == RC_OK) {
  529.  
  530.                     if (answer->rm_Result2) {
  531.  
  532.                         if (buffer)
  533.                             strcpy(buffer, (char *)answer->rm_Result2);
  534.  
  535.                         DeleteArgstring((char *)answer->rm_Result2);
  536.                     }
  537.                 }
  538.  
  539.                 DeleteArgstring((char *)ARG0(answer));
  540.  
  541.                 DeleteRexxMsg(answer);
  542.  
  543.                 return(&result);
  544.             }
  545.         }
  546.     }
  547.  
  548.     Permit();
  549.  
  550.     return(NULL);
  551. }
  552.  
  553. ///
  554. /// "misc"
  555.  
  556. /* ---------------------------------- EvaluateBool -----------------------------
  557.  
  558.  Translate boolean string
  559.  
  560. */
  561.  
  562. BOOL
  563. EvaluateBool(arg, value)
  564.  
  565. UBYTE *arg;
  566. BOOL   value;
  567. {
  568.     if (arg) {
  569.  
  570.         if (stricmp(arg, "TOGGLE"))
  571.             value = (stricmp(arg, "TRUE") == 0);
  572.         else
  573.             value = !value;
  574.     }
  575.  
  576.     return(value);
  577. }
  578.  
  579.  
  580. ///
  581.